//
//  CZEmociton.swift
//  01.表情键盘
//
//  Created by Apple on 15/12/27.
//  Copyright © 2015年 Apple. All rights reserved.
//

import UIKit

/// 表情包模型
class CZEmoticonPackage: NSObject {
    /// id表情包的文件夹名称
    var id: String
    
    /// 表情包的名称
    var group_name_cn: String?
    
    /// 所有的表情模型
    var emoticons: [CZEmociton] = [CZEmociton]()
    
    /// 表情包构造函数
    init(id: String) {
        self.id = id
        super.init()
    }
    
    // 获取 Emoticons.bundle 的路径 直接查找
    static let bundlePath = NSBundle.mainBundle().pathForResource("Emoticons", ofType: "bundle")!
    
    // 只让表情包加载一次
    static let packages = CZEmoticonPackage.loadPackages()
    
    /// 加载所有的表情包模型,会调用多次,每次都从磁盘加载需要消耗性能
    private class func loadPackages() -> [CZEmoticonPackage]? {
        print("加载表情包----------")
        // 1. 加载到emoticons.plist,可以知道有每个表情包的文件夹名称
        
        // 1.1 拼接emoticons.plist的路径 bundlePath/emoticons.plist
        let plistPath = (bundlePath as NSString).stringByAppendingPathComponent("emoticons.plist")
        
        // 1.2 读取emoticons.plist里面的每个表情包文件夹名称
        let emoticonDict = NSDictionary(contentsOfFile: plistPath)!

        // 1.3 获取packages所对应的value是一个数组,数组里面存放的是字典
        if let array = emoticonDict["packages"] as? [[String: AnyObject]] {
            // 定义数组保存表情包模型
            var packages = [CZEmoticonPackage]()
            
            // 创建 最近 表情包
            let recentPackage = CZEmoticonPackage(id: "")
            
            // 最近 表情包添加名称
            recentPackage.group_name_cn = "最近"
            
            // 添加到表情包数组最前面
            packages.append(recentPackage)
            
            // 最近 表情包 添加空白表情和删除按钮
            recentPackage.appendEmptyEmoticon()
            
            // 1.4 遍历数组里面的元素
            for dict in array {
                let id = dict["id"] as! String
                // 1.5 创建表情包
                let package = CZEmoticonPackage(id: id)
                
                // 1.6 表情包加载表情
                package.loadEmoticon()
                
                packages.append(package)
            }
            
            // 返回所有的表情包模型
            return packages
        }
        
        return nil
    }
    
    /// 加载所有的表情,加载表情包的名称
    func loadEmoticon() {
        // 2.1 info.plist全路径 = bundlePath + id + info.plist
        let infoPlistPath = ((CZEmoticonPackage.bundlePath as NSString).stringByAppendingPathComponent(id) as NSString).stringByAppendingPathComponent("info.plist")

        // 2.2 加载info.plist数据
        let infoDict = NSDictionary(contentsOfFile: infoPlistPath)!
        
        // 2.3 获取表情包名称
        group_name_cn = infoDict["group_name_cn"] as? String
        
        // 加载所有的表情
        // 2.4 获取表情模型数组
        if let emoticonsArray = infoDict["emoticons"] as? [[String: AnyObject]] {
            var index = 0
            
            // 2.5 遍历获取每一个表情对应的字典
            for dict in emoticonsArray {
                // 2.6 字典转模型,传入表情包文件夹名称id
                let emoticon = CZEmociton(id: id, dict: dict)
                
                // 2.7 将表情模型添加到表情模型数组里面
                emoticons.append(emoticon)
                
                index++
                // 2.8 如果是第21个表情就添加删除按钮
                if index == 20 {
                    // 每页的最后一个,添加一个删除模型
                    emoticons.append(CZEmociton(removeEmoticon: true))
                    
                    // 清空index,从0开始算起
                    index = 0
                }
            }
        }
        
        // 在加载完所有表情之后判断最后一页是否满21个,不满就添加空白按钮和删除按钮
        appendEmptyEmoticon()
    }
    
    /// 当表情包最后一页不满21个时,需要添加空白按钮和一个删除按钮
    func appendEmptyEmoticon() {
        // 判断表情包最后一页是不是满21个
        let count = emoticons.count % 21
        
        // count == 0 表示正好满一页
        // count != 0 表示最后一页有count个表情
        // 最近表情包里面没有表情  emoticons.count % 21 = 0
        // 一个表情都没有的表情包需要添加20个空的表情和一个删除按钮
        if count > 0 || emoticons.count == 0 {
            // 表示最后一页有count个表情
            // count == 1,需要添加19(20 - 1)(1..<20)个空白表情和一个删除按钮
            // count == 2,需要添加18(20 - 2)(2..<20)个空白表情和一个删除按钮
            // 添加空白按钮
            for _ in count..<20 {
                // 创建空白按钮,添加到现有表情的后面
                emoticons.append(CZEmociton(removeEmoticon: false))
            }
            
            // 添加删除按钮
            emoticons.append(CZEmociton(removeEmoticon: true))
        }
    }
    
    /// 添加表情模型到最近表情包
    class func addFavorateEmoticon(emoticon: CZEmociton) {
        // 删除按钮不需要添加到最近表情
        if emoticon.removeEmoticon {
            return
        }
        
        // 空白按钮不需要排序,不能通过emoticon.removeEmoticon == false来判断是空表情
        if emoticon.pngPath == nil && emoticon.emoji == nil {
            return
        }
        
        // 最近表情包,只有21个表情.而且最后一个是删除按钮,删除按钮不需要进行排序
        // 1.将表情使用次数加1
        emoticon.times++
        
        // 2.获取到最近表情包模型里面的所有表情模型
        var recentEmoticons = packages![0].emoticons
        
        // 3.将删除按钮移除数组,不参与排序
        let removeEmoticon = recentEmoticons.removeLast()
        
        // 4.contains判断数组中是否存在某个元素
        let contains = recentEmoticons.contains(emoticon)
        
        // 5.最近表情包里面没有这个表情才需要添加表情
        if !contains {
            recentEmoticons.append(emoticon)
        }
        
        // 6.数组排序,需要重新赋值
        recentEmoticons = recentEmoticons.sort { (e1, e2) -> Bool in
            // 根据模型的times降序排序,使用次数多的排在前面,次数少的排在后面
            return e1.times > e2.times
        }
        
        // 7.如果上面有添加表情,在排序之后需要删除一个表情,保证最近表情包里面的表情数量固定
        if !contains {
            // 移除最后一个使用次数最少的表情
            recentEmoticons.removeLast()
        }
        
        // 8.将删除按钮添加回来,在第21个位置
        recentEmoticons.append(removeEmoticon)
        
        print("添加后的最近表情包:\(recentEmoticons.count),\(recentEmoticons)")
        // 千万要记得重新赋值.recentEmoticons 改变 packages![0].emoticons不会跟着改
        packages![0].emoticons = recentEmoticons
    }
    
    // 对象的打印
    override var description: String {
//        let p = ["id", "group_name_cn", "emoticons"]
//        return "\n\t表情包模型: \(dictionaryWithValuesForKeys(p))"
        return "\n\t表情包模型: id:\(id), group_name_cn: \(group_name_cn), emoticons: \(emoticons))"
    }
}

/// 表情模型
class CZEmociton: NSObject {
    /// id 表情包文件夹名称
    var id: String?
    
    /// 表情名称,用于网络传输
    var chs: String?
    
    /// 表情图片名称
    var png: String? {
        didSet {
            // 当kvc设置png时,来拼接完整地图片路径
            // 完整地图片路径 = bundlePath + id + 图片名称
            pngPath = CZEmoticonPackage.bundlePath + "/\(id!)/\(png!)"
        }
    }
    
    /// 表情图片的完整路径
    var pngPath: String?
    
    /// code用于显示emoji表情
    var code: String? {
        didSet {
            // kvc设置code之后,将code转成emoji表情
            // 创建扫描器
            let scanner = NSScanner(string: code!)
            
            // 扫描
            var result: UInt32 = 0
            scanner.scanHexInt(&result)
            let scalar = UnicodeScalar(result)
            
            let c = Character(scalar)
            emoji = String(c)
        }
    }
    
    /// emoji的字符串
    var emoji: String?
    
    /// 表情的使用次数,使用次数多的会显示在最近表情包的最前面
    var times = 0
    
    /// true 是删除按钮, false 是空白按钮
    var removeEmoticon = false
    
    /// 模型显示删除按钮和空白表情,true 是删除按钮, false 是空白按钮
    init(removeEmoticon: Bool) {
        self.removeEmoticon = removeEmoticon
        super.init()
    }
    
    /// 字典转模型,可以显示图片和emoji表情
    init(id: String?, dict: [String: AnyObject]) {
        super.init()
        
        self.id = id
        // 使用KVC赋值
        setValuesForKeysWithDictionary(dict)
    }
    
    // 字典的key在模型中找不到对应的属性
    override func setValue(value: AnyObject?, forUndefinedKey key: String) {}
    
    // 对象打印方法
    override var description: String {
        return "\n\t\t表情模型:chs: \(chs), png: \(png), code: \(code), removeEmoticon:\(removeEmoticon), times: \(times)"
    }
}
